/**
 * User: Matt
 * Date: Oct 21, 2010
 * Time: 7:50:44 PM
 * Description: This is the main frame for RapidRails
 */

import Utilities.ButtonProperties;
import Utilities.FileOperations;
import Utilities.TitledPanel;
import Utilities.VirtualButton;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.List;

//import statements

//Check if window closes automatically. Otherwise add suitable code
public class MainWindow
{

    JFrame jFrame;

    JTabbedPane tabbedPane;
    JPanel migrations;
    JPanel searchPane;
    JPanel viewPane;
    JMenuBar menuBar;


    JPanel propertiesPane;
    JTextPane editorPane;

    JList migrationsDataList;
    JList migrationsKeyList;

    JScrollPane scrollPaneLeft;
    JScrollPane scrollPaneRight;

    SyntaxDocument syntaxDocument;
    JSplitPane splitPane;
    private JPanel rightPane;

    ButtonProperties buttonProperties;

    public static void main( String args[] ) {
        new MainWindow();
    }

    MainWindow() {

        //Creates all the window buttons
        initializeButtons();

        //Create the main window of our program
        jFrame = new JFrame();

        //Set the app to close when we hit the X
        jFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

        //Set look and feel to be native on our OS rather than the ugly swing default.
        setLookAndFeel();

        //Initialize all our Panels
        propertiesPane = new JPanel();
        migrations = new JPanel();
        searchPane = new JPanel();
        viewPane = new JPanel();
        rightPane = new JPanel();

        //Create our text editor
        editorPane = new JTextPane();

        //Create tabs for our side window
        tabbedPane = new JTabbedPane();

        //Create the main menu
        menuBar = new JMenuBar();

        //Set the layout on the migrations panel which is a tab
        migrations.setLayout( new BoxLayout( migrations, BoxLayout.Y_AXIS ) );

        //Add a the menu to our main window
        jFrame.add( menuBar, BorderLayout.NORTH );

        //Add Our menu items -> Needs to be it's own method. This is ugly.
        JMenu menu = new JMenu( "File" );

        //Create our menu items
        JMenuItem open = new JMenuItem( "Open" );

        //Add the action of opening a file when we click on open.
        open.addActionListener( new ActionListener()
        {
            public void actionPerformed( ActionEvent e ) {

                JFileChooser fileChooser = new JFileChooser();
                int returnMe = fileChooser.showOpenDialog( jFrame );

                //See if the user picked a file and if so put it in our editor.
                if( returnMe == JFileChooser.APPROVE_OPTION )
                {
                    //Put the file's text in our editor.
                    editorPane.setText( FileOperations.returnStringFromFile( fileChooser.getSelectedFile() ) );
                }

            }
        } );
        //Add our menu items to the menu
        menu.add( open );
        menuBar.add( menu );

        //Add all our tab panes
        addTabsToTabbedPane();
        createSearchPane();
        createViewPane();
        createMigrationsPane();

        //Create our pane that includes the search box and all the tabs.
        createRightPane();

        //Create the document that will do all our validation and color coding.
        createStyledDocument();

        //Create the overall split panes for the window.
        createSplitPanes();

        //Set a default size to our main window
        jFrame.setSize( 1200, 800 );
        // pack();
        jFrame.setVisible( true );

        //Tell it how much real estate we should have on the left and the right.
        splitPane.setDividerLocation( 0.8d );
    }

    private void initializeButtons() {
        buttonProperties = new ButtonProperties();
    }

    private void createViewPane() {

        //Sets a box layout for the view pane
        viewPane.setLayout( new BoxLayout( viewPane, BoxLayout.X_AXIS ) );

        // Get a list of all the titled panels we will be creating
        List<TitledPanel> titledPanels = buttonProperties.getTitledPanels();

        //Go through all the titled panels, create them and add their buttons
        for( TitledPanel titledPanel : titledPanels )
        {
            //Create the UI for the TitledPanel object
            JPanel jPanel = createTitledPanel( titledPanel.getTitle(), BoxLayout.Y_AXIS );

            //Get all the virtual buttons
            List<VirtualButton> viewButtons = titledPanel.getButtons();

            //Go through all the buttons and create the UI version
            for( VirtualButton viewButton : viewButtons )
            {
                createButton( jPanel, viewButton.getDisplayName(), viewButton.getCodeToInsert() );
            }
            //Add the completed frames to the panel
            viewPane.add( jPanel );
        }



    }

    //Creates a titled panel UI object and returns it
    JPanel createTitledPanel( String title, int axis ) {

        //Create the UI Object
        JPanel panel = new JPanel();

        //Set the panel's layout
        panel.setLayout( new BoxLayout( panel, axis ) );

        //Add the text at the top of the panel
        panel.setBorder( BorderFactory.createTitledBorder( title ) );
        return panel;
    }

    //Creates a button that goes into a titled panel
    private void createButton( Container container, String name, final String codeToInsert ) {

        //Create the button and give it it's display name.
        JButton button = new JButton( name );

        //Set it's default alignment
        button.setAlignmentX( Component.LEFT_ALIGNMENT );

        //Add the action that if the user hits the button it will insert the snippet code to the editor.
        button.addActionListener( new ActionListener()
        {
            public void actionPerformed( ActionEvent e ) {
                //Insert the snippet to the editor.
                syntaxDocument.insertDefaultText( editorPane.getCaretPosition(), codeToInsert );
            }
        } );

        //Add to whoever we are asking it to.
        container.add( button );
    }

    //Creates and adds the panes for the main panel on the right.
    private void createRightPane() {
        //Sets the layout for the panel
        rightPane.setLayout( new BoxLayout( rightPane, BoxLayout.Y_AXIS ) );

        //Add it's search box and the pane that contains all the tabs
        rightPane.add( searchPane );
        rightPane.add( tabbedPane );
    }

    //Creates the pane we use to search google.
    private void createSearchPane() {

        //Set the layout for the search panel
        searchPane.setLayout( new BoxLayout( searchPane, BoxLayout.X_AXIS ) );

        //Set the maximumsize for the search box so that it's not bigger than it should be.
        searchPane.setMaximumSize( new Dimension( 2000, 30 ) );

        //Create the actual search text box
        final JTextField searchField = new JTextField();

        //Create the button we can push to search
        JButton searchButton = new JButton( "Search" );

        //Add the listener so we can act when they click on the box itself.
        searchField.addKeyListener( new KeyAdapter()
        {
            public void keyPressed( java.awt.event.KeyEvent evt ) {
                //If the user presses enter then open the browser to the address in the searchField.
                if( evt.getKeyCode() == evt.VK_ENTER )
                    openBrowser( searchField );

            }
        } );

        //Listen for mouse presses on the searchButton and open the browser if the user clicks it.
        searchButton.addMouseListener( new MouseListener()
        {
            public void mouseClicked( MouseEvent
                    e ) {
                openBrowser( searchField );

            }

            public void mousePressed( MouseEvent e ) {

            }

            public void mouseReleased( MouseEvent e ) {

            }

            public void mouseEntered( MouseEvent e ) {

            }

            public void mouseExited( MouseEvent e ) {

            }
        } );

        //Add the searchField and searchButton to the searchPane.
        searchPane.add( searchField );
        searchPane.add( searchButton );
    }

    //The actual code to open the browser
    private void openBrowser( JTextField searchField ) {

        //The url we are going to search
        String link = "http://www.google.com/search?q=";
        try
        {
            //Search Google for the text string we are wanting to search for.
            Runtime.getRuntime().exec( "rundll32 url.dll,FileProtocolHandler " + link + searchField.getText() );
        } catch( IOException e1 )
        {
            e1.printStackTrace();
        }
    }

    //Sets the look and feel to be windows friendly and not ugly swing default.
    private void setLookAndFeel() {
        try
        {
            UIManager.setLookAndFeel(
                    "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" );
        } catch( Exception e )
        {
        }
    }

    //Creates the split panes our 2 main windows will go in.
    private void createSplitPanes() {
        //Create the left and right scroll panes that will go in the split panes.
        scrollPaneLeft = new JScrollPane( editorPane );
        scrollPaneRight = new JScrollPane( rightPane );

        //Create a new split pane.
        splitPane = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, scrollPaneLeft, scrollPaneRight );

        //add our splitPane to our main window.
        jFrame.add( splitPane, BorderLayout.CENTER );

        //Set the minimum size of the two scroll panes.
        scrollPaneLeft.setMinimumSize( new Dimension( 0, 0 ) );
        scrollPaneRight.setMinimumSize( new Dimension( 0, 0 ) );

    }

    //This creates our syntax document so we can have source code highlighting.
    private void createStyledDocument() {

        //Create syntax document
        syntaxDocument = new SyntaxDocument();

        //Set our editors document syntax document that provides the code highlighting.
        editorPane.setStyledDocument( syntaxDocument );
    }

    //Create the pane for the migrations tab
    private void createMigrationsPane() {

        //Add two panels, one for the top and the other for the bottom.
        JPanel migrationsTop = new JPanel();
        JPanel migrationsBottom = new JPanel();

        //Set the layout and border title on the top object.
        migrationsTop.setLayout( new BoxLayout( migrationsTop, BoxLayout.Y_AXIS ) );
        migrationsTop.setBorder( BorderFactory.createTitledBorder( "Create Migration" ) );

        //Set the layout and border title on the bottom object.
        migrationsBottom.setLayout( new BoxLayout( migrationsBottom, BoxLayout.Y_AXIS ) );
        migrationsBottom.setBorder( BorderFactory.createTitledBorder( "Valid Data Types" ) );

        //Create our default set of data that will populate the top and bottom list boxess
        String[] data = { "create_table", "change_table", "drop_table", "add_column", "change_column", "rename_column", "remove_column", "add_index", "remove_index" };
        String[] keywords = { ":primary_key", ":string", ":integer", ":float",
                ":decimal", ":datetime", ":timestamp", ":time", ":date", ":binary", ":boolean" };

        //Create a list that will hold our data words for the top list.
        migrationsDataList = new JList( data );

        //Create a list that will hold the keywords for the bottom list.
        migrationsKeyList = new JList( keywords );

        //Create the scroll dataPane that will hold our migrationsDataList
        JScrollPane dataPane = new JScrollPane( migrationsDataList );

        //Insert the template code when the user clicks an item on the data list.
        migrationsDataList.addMouseListener( new MouseListener()
        {

            public void mouseClicked( MouseEvent e ) {

                String insertMe = "class CreateProducts < ActiveRecord::Migration\n" +
                        "  def self.up\n" +
                        "    create_table :products do |t|\n" +
                        "      t.string :name\n" +
                        "      t.text :description\n" +
                        "\n" +
                        "      t.timestamps\n" +
                        "    end\n" +
                        "  end\n" +
                        "\n" +
                        "  def self.down\n" +
                        "    drop_table :products\n" +
                        "  end\n" +
                        "end";
                try
                {
                    syntaxDocument.insertDefaultText( editorPane.getCaretPosition(), insertMe );
                } catch( Exception e1 )
                {
                    e1.printStackTrace();
                }

            }

            public void mousePressed( MouseEvent e ) {

            }

            public void mouseReleased( MouseEvent e ) {

            }

            public void mouseEntered( MouseEvent e ) {

            }

            public void mouseExited( MouseEvent e ) {

            }
        } );

        //Create the migrations keylist pane that will hold our key list
        JScrollPane keyPane = new JScrollPane( migrationsKeyList );
        migrationsKeyList.addMouseListener( new MouseListener()
        {
            public void mouseClicked( MouseEvent e ) {
                try
                {

                    syntaxDocument.insertDefaultText( editorPane.getCaretPosition(), (String) migrationsKeyList.getSelectedValue() );

                }
                catch( Exception a )
                {
                    a.printStackTrace();
                }
            }

            public void mousePressed( MouseEvent e ) {

            }

            public void mouseReleased( MouseEvent e ) {

            }

            public void mouseEntered( MouseEvent e ) {

            }

            public void mouseExited( MouseEvent e ) {

            }
        } );

        //Add the data and key panes to the top and bottom panels respectively.
        migrationsTop.add( dataPane );
        migrationsBottom.add( keyPane );

        //Add the panels that hold the top and bottom panels to the migrations tab panel
        migrations.add( migrationsTop );
        migrations.add( migrationsBottom );
    }

    //Creates all the tabs and gives each one it's corresponding pane
    private void addTabsToTabbedPane() {


        tabbedPane.addTab( "Main Tab", propertiesPane );
        tabbedPane.addTab( "Controller", new Component()
        {
        } );
        tabbedPane.addTab( "Migrations", migrations );
        tabbedPane.addTab( "Model", new Component()
        {
        } );
        tabbedPane.addTab( "View", viewPane );
    }
}